﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JeanFish.Common.Model.Computer.Format
{
    /// <summary>
    /// 表示RIFF文件格式的抽象类型。
    /// </summary>
    public abstract class RIFF : System.Collections.IEnumerable
    {
        /// <summary>
        /// 根据指定的RIFF文件类型和文件数据长度初始化新的RIFF实例。
        /// </summary>
        /// <param name="type">文件类型，4字节</param>
        /// <param name="fileSize">文件大小</param>
        public RIFF(char[] type,uint fileSize)
            :this(type,new byte[fileSize])
        {
        }
        /// <summary>
        /// 按照指定的RIFF文件类型和文件数据初始化RIFF文件实例。
        /// </summary>
        /// <param name="type">文件类型，4字节</param>
        /// <param name="data">文件数据，RIFF文件字节</param>
        public RIFF(char[] type, byte[] data)
        {
            this.Data = data;
            this.RIFFHeader = new HeaderChunk(this, type);
            Chunks.Add(RIFFHeader);
        }

        /// <summary>
        /// 表示RIFF块Chunk的类型。
        /// </summary>
        public abstract class RIFFChunk
        {
            #region const
            /// <summary>
            /// 表示块标识符字节长度。
            /// </summary>
            protected const byte IDLength = 4;
            /// <summary>
            /// 表示块标识符字节起始位置。
            /// </summary>
            protected const byte IDIndex = 0;
            /// <summary>
            /// 表示块大小字节长度。
            /// </summary>
            protected const byte SizeLength = 4;
            /// <summary>
            /// 表示块大小字节起始位置。
            /// </summary>
            protected const byte SizeIndex = 4;
            #endregion
            /// <summary>
            /// 表示块所属的RIFF文件引用。
            /// </summary>
            protected RIFF RIFF = null;
            /// <summary>
            /// 初始化RIFF块。
            /// </summary>
            /// <param name="riff">块所属的RIFF文件</param>
            /// <param name="chunkIndex">块在RIFF文件中的起始位置</param>
            /// <param name="chunkSize">块大小</param>
            public RIFFChunk(RIFF riff, int chunkIndex, uint chunkSize)
            {
                this.RIFF = riff;
                this.StartIndex = chunkIndex;
                this.data = new ExtendedArray<byte>(riff.Data, chunkIndex, (int)chunkSize);
                //this.Size = chunkSize - 8;
            }
            /// <summary>
            /// 表示块的数据。
            /// </summary>
            internal ExtendedArray<byte> data;
            /// <summary>
            /// 表示块在RIFF文件中的初始位置。
            /// </summary>
            public int StartIndex { get; protected set; }
            /// <summary>
            /// 表示块标识符，4字节。
            /// </summary>
            public char[] ID
            {
                get
                {
                    return data.Take(IDLength).Select(_ => (char)_).ToArray();
                }
            }
            /// <summary>
            /// 表示块大小。
            /// </summary>
            public UInt32 Size
            {
                get
                {
                    return BitConverter.ToUInt32(data.Skip(IDLength).Take(SizeLength).ToArray(), 0);
                }
                set
                {
                    this.data.Copy(BitConverter.GetBytes(value), 0, SizeIndex, SizeLength);
                }
            }
        }
        /// <summary>
        /// 表示RIFF文件中头块的类型。
        /// </summary>
        public sealed class HeaderChunk : RIFFChunk
        {
            #region const
            private const byte RIFFLength = IDLength;
            private const byte RIFFIndex = IDIndex;
            private const byte TypeLength = 4;
            private const byte TypeIndex = RIFFLength + SizeLength;
            #endregion
            /// <summary>
            /// 初始化RIFF头块。
            /// </summary>
            /// <param name="riff">块所属的RIFF文件</param>
            /// <param name="type">RIFF文件类型，4字节</param>
            public HeaderChunk(RIFF riff,char[] type)
                :base(riff,0,RIFFLength+SizeLength+TypeLength)
            {
                data[0] = (byte)'R';
                data[1] = (byte)'I';
                data[2] = data[3] = (byte)'F';
                this.Size = (uint)(base.RIFF.Data.Length - 8);
                this.data.Copy(type.Select(_=>(byte)_).ToArray(), 0, TypeIndex, TypeLength);
            }
            /// <summary>
            /// 表示RIFF头块起始的"Riff"标识符。
            /// </summary>
            public new char[] RIFF
            {
                get
                {
                    return base.ID;
                }
            }
            /// <summary>
            /// 表示具体的RIFF文件类型。
            /// </summary>
            public char[] Type
            {
                get
                {
                    return data.Skip(TypeIndex).Take(TypeLength).Select(_ => (char)_).ToArray();
                }
            }
        }

        private byte[]  Data;
        /// <summary>
        /// 获取RIFF文件的RIFF头块。
        /// </summary>
        public HeaderChunk RIFFHeader
        {
            get;
            protected set;
        }
        private List<RIFFChunk> Chunks = new List<RIFFChunk>();
        /// <summary>
        /// 获取RIFF文件中的块。
        /// </summary>
        /// <returns>RIFF文件中块的枚举</returns>
        public System.Collections.IEnumerator GetEnumerator()
        {
            foreach (RIFFChunk c in Chunks) yield return c;
        }
        /// <summary>
        /// 获取指定标识符的RIFF块。
        /// </summary>
        /// <param name="ID">RIFF块的标识符</param>
        /// <returns>RIFF块</returns>
        public RIFFChunk this[string ID]
        {
            get
            {
                return Chunks.SingleOrDefault(_ => _.ID.SequenceEqual(ID.ToArray()));
            }
            protected set
            {
                Chunks.Add(value);
            }
        }
    }
}
